package com.hzeport.bgs22emduty.config;

import cn.gov.customs.casp.sdk.h4a.AccreditBeanReaderHelper;
import cn.gov.customs.casp.sdk.h4a.accredit.ws.IAccreditReaderGetChildrenInRolesCupaaFaultArgsFaultFaultMessage;
import cn.gov.customs.casp.sdk.h4a.accredit.ws.OrganizationCategory;
import cn.gov.customs.casp.sdk.h4a.entity.ChildrenInRoles;
import cn.gov.customs.casp.sdk.h4a.entity.Roles;
import cn.gov.customs.casp.sdk.h4a.enumdefines.AccreditCategory;
import cn.gov.customs.casp.sdk.h4a.enumdefines.DelegationCategories;
import cn.gov.customs.casp.sdk.h4a.enumdefines.RoleCategories;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hzeport.bgs22emduty.dto.DutyScheduleInfoTimeDTO;
import com.hzeport.bgs22emduty.entity.*;
import com.hzeport.bgs22emduty.enums.SmsEnum;
import com.hzeport.bgs22emduty.outbound.BaseDeptInfoRepository;
import com.hzeport.bgs22emduty.outbound.BasePersonInfoRepository;
import com.hzeport.bgs22emduty.outbound.ParamSmsTemplateRepository;
import com.hzeport.bgs22emduty.outbound.ScreenMessageRepository;
import com.hzeport.bgs22emduty.service.DutyScheduleInfoService;
import com.hzeport.bgs22emduty.util.MessageSendUtil;
import com.masa.common.core.base.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * websocket的处理类。
 * 作用相当于HTTP请求
 * 中的controller
 */
@Component
@Slf4j
@ServerEndpoint("/api/pushMessage/{userId}")
public class WebSocketServer {

    /**静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。*/
    private static int onlineCount = 0;
    /**concurrent包的线程安全Set，用来存放每个客户端对应的WebSocket对象。*/
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**与某个客户端的连接会话，需要通过它来给客户端发送数据*/
    private Session session;
    /**接收userId*/
    private String userId = "";
    @Resource
    private ScreenMessageRepository screenMessageRepository;
    @Resource
    private BaseDeptInfoRepository baseDeptInfoRepository;
    @Resource
    private BasePersonInfoRepository basePersonInfoRepository;
    @Resource
    private DutyScheduleInfoService dutyScheduleInfoService;
    @Resource
    private ParamSmsTemplateRepository paramSmsTemplateRepository;
    @Resource
    private MessageSendUtil messageSendUtil;
    @Resource
    private SystemConfig systemConfig;

//    communicationheduled(cron = "0 */3 * * * *")
//    private void keepConnection(){
//        webSocketMap.forEach((k,v)->{
//            v.sendMessage("123");
//            log.info("唤醒"+k);
//        });
//        log.info("三分钟一次");
//    }

    /**
     * 连接建立成
     * 功调用的方法
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("userId") String userId) {
        this.session = session;
        this.userId=userId;
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            //加入set中
            webSocketMap.put(userId,this);
        }else{
            //加入set中
            webSocketMap.put(userId,this);
            //在线数加1
            addOnlineCount();
        }
        log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());
        sendMessage("连接成功");
    }

    /**
     * 连接关闭
     * 调用的方法
     */
    @OnClose
    public void onClose() {
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消
     * 息后调用的方法
     * @param message
     * 客户端发送过来的消息
     **/
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户消息:"+userId+",报文:"+message);
        //可以群发消息
        //消息保存到数据库、redis
        if(!StringUtils.isEmpty(message)){
            try {
                //解析发送的报文
                JSONObject jsonObject = JSON.parseObject(message);
                //追加发送人(防止串改)
                jsonObject.put("fromUserId",this.userId);
                String toUserId=jsonObject.getString("toUserId");
                //传送给对应toUserId用户的websocket
                if(!StringUtils.isEmpty(toUserId)&&webSocketMap.containsKey(toUserId)){
                    webSocketMap.get(toUserId).sendMessage(message);
                }else{
                    //否则不在这个服务器上，发送到mysql或者redis
                    log.error("请求的userId:"+toUserId+"不在该服务器上");
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }


    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {

        log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
        error.printStackTrace();
    }

    /**
     * 实现服务
     * 器主动推送
     */
    public void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     *发送自定
     *义消息
     **/
    public static void sendInfo(String message, String userId) {
        log.info("发送消息到:"+userId+"，报文:"+message);
        if(!StringUtils.isEmpty(userId) && webSocketMap.containsKey(userId)){
            webSocketMap.get(userId).sendMessage(message);
        }else{
            log.error("用户"+userId+",不在线！");
        }
    }

    public static void sendAll(String message) {
      for (String key:webSocketMap.keySet()){
          sendInfo(message,key);
      }
    }

    /**
     * 获得此时的
     * 在线人数
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 在线人
     * 数加1
     */
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    /**
     * 在线人
     * 数减1
     */
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public void sendAllHZ(String message,ScreenMessage screenMessage) {
        if (screenMessage!=null) {
            screenMessage.setSendTarget("HZ");
            screenMessage.setDelFlag("0");
            screenMessage.setModule(screenMessage.getModule());
            screenMessageRepository.save(screenMessage);
        }
        for (String key:webSocketMap.keySet()){
            if (key.contains("HZ")) {
                sendInfo(message, key);
            }
        }
        List<ParamSmsTemplate> paramSmsTemplates=paramSmsTemplateRepository.list(new LambdaQueryWrapper<ParamSmsTemplate>()
                .eq(ParamSmsTemplate::getTemplateName,"海关总署")
                .eq(ParamSmsTemplate::getIsSend, "1")
                .eq(ParamSmsTemplate::getSmsType, SmsEnum.TYPE_MESSAGE_UP.getValue()));
        if (!CollectionUtils.isEmpty(paramSmsTemplates)) {
            for (ParamSmsTemplate paramSmsTemplate:paramSmsTemplates) {
                BaseResult<DutyScheduleInfoTimeDTO> dutyScheduleInfoTimeDTOBaseResult =
                        dutyScheduleInfoService.nowUser("海关总署");
                if (dutyScheduleInfoTimeDTOBaseResult != null && dutyScheduleInfoTimeDTOBaseResult.getData() != null &&
                        dutyScheduleInfoTimeDTOBaseResult.getData().getKJInfo() != null
                        && dutyScheduleInfoTimeDTOBaseResult.getData().getKJInfo().getDPhone() != null) {
                    messageSendUtil.sendMessage(dutyScheduleInfoTimeDTOBaseResult.getData().getKJInfo().getDPhone(),screenMessage.getCustomName()+"上报,"+ paramSmsTemplate.getRemark());
                }
            }
        }
    }
    public void sendAllZS(String message,ScreenMessage screenMessage,String module) {
        if (screenMessage!=null) {
            screenMessage.setSendTarget("ZS");
            screenMessage.setDelFlag("0");
            screenMessage.setModule(module);
            screenMessageRepository.save(screenMessage);
        }
        for (String key:webSocketMap.keySet()){
            if (key.contains("ZS")) {
                JSONObject tempJSONOBject=new JSONObject();
                tempJSONOBject.put("msg",message);
                tempJSONOBject.put("id",screenMessage.getId());
                sendInfo(JSONObject.toJSONString(tempJSONOBject), key);
            }
        }
    }

    public void sendAllDistribute( String message , ScreenMessageDistribute screenMessageDistribute , String module ) {

        final AccreditBeanReaderHelper helper = new AccreditBeanReaderHelper();
        ChildrenInRoles[] childrenInRoles = new ChildrenInRoles[0];
        Roles[] roles = new Roles[0];
        log.info(roles+"");
        try {
            roles = helper.getBeanRoles("", AccreditCategory.Code , systemConfig.getAppId(),  AccreditCategory.Code
                    , systemConfig.getViewValues() , AccreditCategory.Code , RoleCategories.All,"");

        } catch ( Exception e ) {
            log.info( "获取此应用下全部角色异常" , e );
        }
        log.info( "获取此应用下全部角色【{}】" , JSONObject.toJSONString( roles ) ) ;

        ScreenMessage screenMessage = new ScreenMessage();
        String customIds = screenMessageDistribute.getCustomId();
        if ( customIds == null ) {
            return;
        }
        String temp[] = customIds.split( "\\|" );
        for ( String customId : temp ) {
            BaseDeptInfo custom = baseDeptInfoRepository.getById( customId );
            log.info( "值班通知短信开始" );
            if(  roles != null && roles.length > 0 ) {
                for ( int i = 0; i < roles.length; i++ ) {
                    log.info( "角色信息{}" , JSONObject.toJSONString( roles[ i ] ) );
                    int index = roles[ i ].getRole_name().indexOf( "值班通知提醒人员" );
                    if ( index != -1 && custom.getDeptName().equals( roles[ i ].getRole_name().substring( 0 , index ) ) ) {
                        log.info( "查询到此角色对应关区名称，进入值班通知短信逻辑" );
                        try {
                            childrenInRoles = helper.getBeanChildrenInRoles( "" , OrganizationCategory.NONE , systemConfig.getAppId() , AccreditCategory.Code , systemConfig.getViewValues() , AccreditCategory.Code , roles[ i ].getCode_name() , AccreditCategory.Code , DelegationCategories.All , "" );
                        } catch ( Exception e ) {
                            log.info( "获取此角色下人员异常" , e );
                        }
                        log.info( "获取到此角色下所有人员{}" , JSONObject.toJSONString( childrenInRoles ) );
                    }

                    if ( childrenInRoles != null && childrenInRoles.length > 0 ) {
                        for ( int j = 0; j < childrenInRoles.length; j++ ) {
                            BasePersonInfo basePersonInfo = basePersonInfoRepository.getOne( new LambdaQueryWrapper< BasePersonInfo >().eq( BasePersonInfo::getUserGuid , childrenInRoles[ j ].getGuid() ) );
                            if ( ! ObjectUtils.isEmpty( basePersonInfo ) ) {
                                log.info( "查询到此人员{}" , JSONObject.toJSONString( basePersonInfo ) );
                                messageSendUtil.sendMessage( basePersonInfo.getPhone() , "总署总值班室发布一条值班通知，请及时办理！" );
                            }
                            else {
                                log.info( "未查询到此人员{}" , JSONObject.toJSONString( childrenInRoles[ i ] ) );
                            }
                        }
                    }
                }
            }

            log.info( "值班提醒短信开始" );
            BaseResult< DutyScheduleInfoTimeDTO > dutyScheduleInfoTimeDTOBaseResult =
                    dutyScheduleInfoService.nowUser( custom.getDeptName() );
            if ( dutyScheduleInfoTimeDTOBaseResult != null && dutyScheduleInfoTimeDTOBaseResult.getData() != null && dutyScheduleInfoTimeDTOBaseResult.getData().getKJInfo() != null && dutyScheduleInfoTimeDTOBaseResult.getData().getKJInfo().getDPhone() != null ) {
                messageSendUtil.sendMessage( dutyScheduleInfoTimeDTOBaseResult.getData().getKJInfo().getDPhone()
                        , "总署总值班室发表一条值班通知，请及时办理" );
            }

            if ( custom != null ) {
                screenMessage.setCustomCode( custom.getId() );
                screenMessage.setCustomName( custom.getDeptName() );
                screenMessage.setRId( screenMessageDistribute.getId() );
                screenMessage.setMessage( screenMessageDistribute.getTitle() );
                if ( screenMessageDistribute != null ) {
                    screenMessage.setSendTarget( "ZS" );
                    screenMessage.setDelFlag( "0" );
                    screenMessage.setMainBody( screenMessageDistribute.getMainBody() );
                    screenMessage.setId(IdUtil.getSnowflake().nextIdStr());
                    screenMessage.setModule( module );
                    screenMessageRepository.save( screenMessage );
                }
                for ( String key : webSocketMap.keySet() ) {
                    if ( key.contains( custom.getId() ) ) {
                        JSONObject tempJSONOBject = new JSONObject();
                        tempJSONOBject.put( "msg" , message );
                        tempJSONOBject.put( "id" , screenMessage.getId() );
                        sendInfo( JSONObject.toJSONString( tempJSONOBject ) , key );
                    }
                }
                //                List<ParamSmsTemplate> paramSmsTemplates=paramSmsTemplateRepository.list(new
                //                LambdaQueryWrapper<ParamSmsTemplate>()
                //                .eq(ParamSmsTemplate::getTemplateCode,custom.getId())
                //                        .eq(ParamSmsTemplate::getIsSend, "1")
                //                        .eq(ParamSmsTemplate::getSmsType, SmsEnum.TYPE_MESSAGE_DOWN.getValue()));
                //                if (!CollectionUtils.isEmpty(paramSmsTemplates)) {
                //                    for (ParamSmsTemplate paramSmsTemplate:paramSmsTemplates) {

                //                    }
                //                }

            }
        }
    }
}


